package com.zombie;

import java.io.InputStream;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.AssetManager;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.Texture.TextureFilter;
import com.badlogic.gdx.graphics.g2d.Animation;
import com.badlogic.gdx.graphics.g2d.Animation2D;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Array;
import com.zombie.util.XMLUtils;

public class ResourceManager extends AssetManager {

	static Map<String,Sprite> sprites = new ConcurrentHashMap<String,Sprite>(); 
	static Map<String,Animation2D> animations = new ConcurrentHashMap<String,Animation2D>(); 
	static Map<String,Sound> sounds = new ConcurrentHashMap<String,Sound>(); 

//	static NodeList listResources;
	private static ResourceManager instance;
	
	public ResourceManager(){
		
	}
	
	
	public static ResourceManager getInstance(){
		if (instance == null)
			instance = new ResourceManager();
		return instance;
	}
	
	public void init() {
		loadResources(Gdx.files.internal("data/data/resources.xml").read());
		Gdx.app.log("INFO", "ResourceManager init");
		Gdx.app.log("INFO", "    Sprites: "+sprites.size());
		Gdx.app.log("INFO", "    Animations: "+animations.size());
		Gdx.app.log("INFO", "    Sounds: "+sounds.size());
	}
	
	
	public static void loadResources(InputStream is){
		Document doc = XMLUtils.getDocumentForStream(is);
        doc.getDocumentElement ().normalize ();
        NodeList listResources = doc.getElementsByTagName("resource");
        
        for(int i = 0;i < listResources.getLength(); i++){
        	Node resourceNode = listResources.item(i);
        	if(resourceNode.getNodeType() == Node.ELEMENT_NODE){
        		Element resourceElement = (Element)resourceNode;
             	addResource(resourceElement);
        	}
        }
	}
	
	private static void addResource(Element resourceElement) {
		String type = resourceElement.getAttribute("type");
		if(type.equals("image")){
			addElementAsImage(resourceElement);
		}else if(type.equals("animation")){
			addElementAsAnimation(resourceElement);
		}else if(type.equals("sprite")){
			addElementAsSprite(resourceElement);
		}else if(type.equals("sound")){
			addElementAsSound(resourceElement);
		}
//		}else if(type.equals("text")){
//			addElementAsText(resourceElement);
//		}else if(type.equals("font")){
//
//		}else if(type.equals("animation")){
//			addElementAsAnimation(resourceElement);
//		}else if(type.equals("sprite")){
//			addElementAsSprite(resourceElement);
//		}else if(type.equals("particle")){
//			addElementAsParticleSystem(resourceElement);
//		}else if(type.equals("emitter")){
//			addElementAsParticleEmitter(resourceElement);
//		}
	}
	
	 public static void addImage(Sprite image, String ID) {
		 sprites.put(ID, image);
	 }
	 
	private static final void addElementAsImage(Element resourceElement){
		loadImage(resourceElement.getAttribute("id"), resourceElement.getTextContent());
	}

	public static Sprite loadImage(String id, String path){
		Texture texture = new Texture(Gdx.files.internal(path));
		texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);

		Sprite image = new Sprite(texture);
		sprites.put(id, image);
		return image;
	}

	public static final Sprite getImage(String ID){
		Sprite img = sprites.get(ID);
		return img;
	}
	
	private static void addElementAsSprite(Element resourceElement) {
		Texture texture = new Texture(Gdx.files.internal(resourceElement.getTextContent()));
		texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
		TextureRegion region = new TextureRegion();
		region.setTexture(texture);
    	int x  =  Integer.parseInt(resourceElement.getAttributes().getNamedItem("x").getNodeValue());
    	int y  =  Integer.parseInt(resourceElement.getAttributes().getNamedItem("y").getNodeValue());
    	int w  =  Integer.parseInt(resourceElement.getAttributes().getNamedItem("w").getNodeValue());
    	int h  =  Integer.parseInt(resourceElement.getAttributes().getNamedItem("h").getNodeValue());
		region.setRegion(x, y, w, h);
		Sprite sprite = new Sprite(region);
    	sprites.put(resourceElement.getAttribute("id"), sprite);
	}
	
	private static void addElementAsAnimation(Element resourceElement){
		try {
			loadAnimation(resourceElement.getAttribute("id"), resourceElement.getTextContent(),
					Integer.valueOf(resourceElement.getAttribute("x")),
					Integer.valueOf(resourceElement.getAttribute("y")),
					Integer.valueOf(resourceElement.getAttribute("tw")),
					Integer.valueOf(resourceElement.getAttribute("th")),
					Integer.valueOf(resourceElement.getAttribute("duration")),
					Integer.valueOf(resourceElement.getAttribute("frames"))
					);
		} catch (NumberFormatException e) {

			e.printStackTrace();
		} catch (DOMException e) {

			e.printStackTrace();
		}
	}
 
	private static void loadAnimation(String id, String spriteSheetPath,
			int x, int y, int tw, int th, int duration, int frames){
		
		Texture texture = new Texture(Gdx.files.internal(spriteSheetPath));
		texture.setFilter(TextureFilter.Linear, TextureFilter.Linear);
		Array<TextureRegion> array = new Array<TextureRegion>();
		int count = 0;
		for(int xx = x/tw; xx < texture.getWidth()/tw;xx++){
			for(int yy = y/th; yy < texture.getHeight()/th;yy++){
				if (frames != 0 && count == frames)
					break;
				if (frames != 0) count++;
				TextureRegion reg = new TextureRegion(texture);
				reg.setRegion(xx*tw, yy*th, tw, th);
				array.add(reg);
			}
		}	 
		Animation2D animation = new Animation2D(duration,array);
		animation.setPlayMode(Animation.LOOP);
		animations.put(id,animation);
	}
 
	public static final Animation2D getAnimation(String ID){
		return animations.get(ID);
	}
	
	private static void addElementAsSound(Element resourceElement){
		loadSound(resourceElement.getAttribute("id"), resourceElement.getTextContent());
	}
 
	public static Sound loadSound(String id, String path){
		Sound sound = Gdx.audio.newSound(Gdx.files.internal(path));
		sounds.put(id, sound);
		return sound;
	}
 
	public static final Sound getSound(String ID){
		return sounds.get(ID);
	}

}
